using System;
using System.Collections.Generic;
using System.Text;

namespace EuropeEngulfed.NET
{
    class ForcePool
    {
        private List<Block> blocksInPool;
        private List<GroundSupportUnit> GSUInPool;
        private MapInfo.CountryID country;
        private int currentSpecialActions;
        private int maxSpecialActions;
        private int currentBeachHeads;
        private int maxBeachHeads;
        private bool poolFactoryLocked;

        public ForcePool(MapInfo.CountryID validCountry)
        {
            poolFactoryLocked = false;
            blocksInPool = new List<Block>();
            GSUInPool = new List<GroundSupportUnit>();
            country = validCountry;
            currentSpecialActions = 0;
            currentBeachHeads = 0;
        }

        public bool PoolFactoryLock
        {
            set
            {
                poolFactoryLocked = value;
            }
        }

        public int CurrentBeachHeads
        {
            get
            {
                return currentBeachHeads;
            }
        }

        public bool GetSpecialAction()
        {
            if (currentSpecialActions > 0)
            {
                currentSpecialActions--;
                return true;
            }
            return false;
        }

        public int MaxSpecialActions
        {
            get
            {
                return maxSpecialActions;
            }

            set
            {
                maxSpecialActions = value;
                if (currentSpecialActions > maxSpecialActions)
                    currentSpecialActions = maxSpecialActions;
            }
        }

        public void ReturnSpecialAction()
        {
            if(currentSpecialActions < maxSpecialActions)
                currentSpecialActions++;
        }

        public bool GetBeachhead()
        {
            if (currentBeachHeads > 0)
            {
                currentBeachHeads--;
                return true;
            }
            return false;
        }

        public void ReturnBeachHead()
        {
            if(currentBeachHeads < maxBeachHeads)
                currentBeachHeads++;
        }

        public List<PlayingPiece> GetCopyOfEuropeEngulfedPlayingPieces()
        {
            List<PlayingPiece> listToReturn = new List<PlayingPiece>();
            foreach (Block block in blocksInPool)
            {
                Block copiedBlock = block.Copy();
                copiedBlock.CurrentStrength = copiedBlock.MaxStrength;
                copiedBlock.OutOfSupplyState = PlayingPiece.OOSState.InSupply;
                listToReturn.Add(copiedBlock);
            }

            foreach (GroundSupportUnit GSU in GSUInPool)
            {
                GroundSupportUnit GSUCopy = GSU.Copy();
                GSUCopy.OutOfSupplyState = PlayingPiece.OOSState.InSupply;
                listToReturn.Add(GSUCopy);
            }

            return listToReturn;
        }

        public Block GetBlock(MapInfo.CountryID countryOwner,Block.BlockType blockType, uint maxStrength)
        {
            foreach (Block block in blocksInPool)
            {
                if(block.CountryOwner == countryOwner)
                    if(block.getBlockType() == blockType)
                        if(block.MaxStrength == maxStrength)
                        {
                            blocksInPool.Remove(block);
                            return block;
                        }
            }
            return null;
        }

        public void ReturnBlock(Block block)
        {
            if(block != null)
                blocksInPool.Add(block);
        }

        public GroundSupportUnit GetGSU(MapInfo.CountryID countryOwner)
        {
            foreach (GroundSupportUnit GSU in GSUInPool)
            {
                if(GSU.CountryOwner == countryOwner)
                {
                    GSUInPool.Remove(GSU);
                    return GSU;
                }
            }
            return null;
        }

        public void ReturnGSU(GroundSupportUnit GSU)
        {
            if (GSU != null)
                GSUInPool.Add(GSU);
        }

        private bool IsValidBlockType(MapInfo.CountryID countryOwner,Block.BlockType blockType, uint maxStrength)
        {
            if(maxStrength > 0 && maxStrength <= 4)
            {
                switch (blockType)
                {
                    case Block.BlockType.militia:
                        {
                            if (countryOwner == MapInfo.CountryID.GreatBritain || countryOwner == MapInfo.CountryID.Germany)
                            {
                                if (maxStrength <= 2)
                                    return true;
                            }
                        }
                        break;
                    case Block.BlockType.infantry:
                        {
                            switch (maxStrength)
                            {
                                case 2:
                                    if (countryOwner != MapInfo.CountryID.USA && countryOwner != MapInfo.CountryID.GreatBritain)
                                        return true;
                                    break;
                                case 3:
                                    if(countryOwner != MapInfo.CountryID.Bulgaria)
                                        return true;
                                    break;
                                case 4:
                                    if (countryOwner == MapInfo.CountryID.France || countryOwner == MapInfo.CountryID.Germany
                                        || countryOwner == MapInfo.CountryID.USA || countryOwner == MapInfo.CountryID.USSR ||
                                        countryOwner == MapInfo.CountryID.Finland || countryOwner == MapInfo.CountryID.GreatBritain)
                                        return true;
                                    break;
                            }
                        }
                        break;
                    case Block.BlockType.cavalry:
                        {
                            switch(maxStrength)
                            {
                                case 2:
                                    if (countryOwner == MapInfo.CountryID.Germany || MapInfo.IsNeutralCountry(countryOwner))
                                        return true;
                                    break;
                                case 3:
                                    if (countryOwner == MapInfo.CountryID.USSR)
                                        return true;
                                    break;
                            }
                        }
                        break;
                    case Block.BlockType.armor:
                        {
                            switch(maxStrength)
                            {
                                case 2:
                                    if (countryOwner == MapInfo.CountryID.France || countryOwner == MapInfo.CountryID.USSR || countryOwner == MapInfo.CountryID.Rumania
                                        || countryOwner == MapInfo.CountryID.Italy || MapInfo.IsNeutralCountry(countryOwner))
                                        return true;
                                    break;
                                case 3:
                                    if (countryOwner == MapInfo.CountryID.France || countryOwner == MapInfo.CountryID.Germany || countryOwner == MapInfo.CountryID.GreatBritain
                                        || countryOwner == MapInfo.CountryID.USSR || countryOwner == MapInfo.CountryID.Italy || countryOwner == MapInfo.CountryID.USA)
                                        return true;
                                    break;
                                case 4:
                                    if (countryOwner == MapInfo.CountryID.Germany || countryOwner == MapInfo.CountryID.GreatBritain
                                    || countryOwner == MapInfo.CountryID.USSR || countryOwner == MapInfo.CountryID.USA)
                                        return true;
                                    break;
                            }
                        }
                        break;
                    case Block.BlockType.airborne:
                        {
                            switch(maxStrength)
                            {
                                case 2:
                                    if (countryOwner == MapInfo.CountryID.Italy || countryOwner == MapInfo.CountryID.Germany
                                        || countryOwner == MapInfo.CountryID.GreatBritain || countryOwner == MapInfo.CountryID.USA
                                        || countryOwner == MapInfo.CountryID.USSR)
                                        return true;
                                    break;
                                case 3:
                                    if (countryOwner == MapInfo.CountryID.Germany
                                    || countryOwner == MapInfo.CountryID.GreatBritain || countryOwner == MapInfo.CountryID.USA
                                    || countryOwner == MapInfo.CountryID.USSR)
                                        return true;
                                    break;
                            }
                        }
                        break;
                    case Block.BlockType.eliteInfantry:
                        if (maxStrength == 4 && (countryOwner == MapInfo.CountryID.Germany || countryOwner == MapInfo.CountryID.USSR))
                            return true;
                        break;
                    case Block.BlockType.eliteArmor:
                        if (maxStrength == 3 && countryOwner == MapInfo.CountryID.Germany)
                            return true;
                        else if (maxStrength == 4 && (countryOwner == MapInfo.CountryID.Germany || countryOwner == MapInfo.CountryID.USSR))
                            return true;
                        break;
                }
            }
            return false;
        }

        public void CreateBeachHeads(int numBeachHeads)
        {
            if (!poolFactoryLocked)
            {
                currentBeachHeads = numBeachHeads;
                maxBeachHeads = numBeachHeads;
            }
            else
                throw new Exception("Pool Factory Locked");
        }

        public void CreateSpecialActions(int numSpecialActions)
        {
            if (!poolFactoryLocked)
            {
                currentSpecialActions = numSpecialActions;
                maxSpecialActions = numSpecialActions;
            }
            else
                throw new Exception("Pool Factory Locked");
        }

        public void CreateGSUInPool(MapInfo.CountryID countryOwner,uint numGSU)
        {
            if (!poolFactoryLocked)
            {
                if (countryOwner == this.country)
                {
                    while (numGSU > 0)
                    {
                        GroundSupportUnit GSUToAdd = new GroundSupportUnit(countryOwner);
                        GSUInPool.Add(GSUToAdd);
                        numGSU--;
                    }
                }
                else
                {
                    throw new Exception("Invalid country GSU added to pool");
                }
            }
            else
                throw new Exception("Pool Factory Locked");
        }

        public void CreateBlocksInPool(MapInfo.CountryID countryOwner,Block.BlockType blockType, uint maxStrength, int numBlocks)
        {
            if(!poolFactoryLocked)
            {
                if (countryOwner == this.country)
                {
                    if (IsValidBlockType(countryOwner, blockType, maxStrength))
                    {
                        while (numBlocks > 0)
                        {
                            Block blockToCreate = null;
                            switch (blockType)
                            {
                                case Block.BlockType.militia:
                                    blockToCreate = new MilitiaBlock(countryOwner, maxStrength);
                                    break;
                                case Block.BlockType.infantry:
                                    blockToCreate = new InfantryBlock(countryOwner, maxStrength);
                                    break;
                                case Block.BlockType.armor:
                                    blockToCreate = new ArmorBlock(countryOwner, maxStrength);
                                    break;
                                case Block.BlockType.cavalry:
                                    blockToCreate = new CavalryBlock(countryOwner, maxStrength);
                                    break;
                                case Block.BlockType.airborne:
                                    blockToCreate = new AirborneBlock(countryOwner, maxStrength);
                                    break;
                                case Block.BlockType.eliteInfantry:
                                    blockToCreate = new EliteInfantryBlock(countryOwner, maxStrength);
                                    break;
                                case Block.BlockType.eliteArmor:
                                    blockToCreate = new EliteArmorBlock(countryOwner, maxStrength);
                                    break;
                                default:
                                    throw new Exception("Unhandled Block Type");
                            }
                            blocksInPool.Add(blockToCreate);
                            numBlocks--;
                        }
                    }
                    else
                        throw new Exception("Invalid block type added");
                }
                else
                {
                    throw new Exception("Invalid country block added to pool");
                }
            }
            else
            {
                throw new Exception("Pool Locked");
            }
        }

        public System.Xml.XmlNode Serialise(System.Xml.XmlDocument xml)
        {
            System.Xml.XmlNode nodeToReturn = xml.CreateElement("ForcePool");
            System.Xml.XmlAttribute countryAttr = xml.CreateAttribute("Country");
            countryAttr.Value = Enum.GetName(typeof(MapInfo.CountryID), this.country);
            nodeToReturn.Attributes.Append(countryAttr);
            System.Xml.XmlNode specialActionsNode = xml.CreateElement("SpecialActions");
            specialActionsNode.InnerText = currentSpecialActions.ToString();
            System.Xml.XmlNode maxSpecialActionsNode = xml.CreateElement("MaxSpecialActions");
            maxSpecialActionsNode.InnerText = maxSpecialActions.ToString();
            System.Xml.XmlNode beachheadsNode = xml.CreateElement("BeachHeads");
            beachheadsNode.InnerText = currentBeachHeads.ToString();
            System.Xml.XmlNode maxBeachheadsNode = xml.CreateElement("MaxBeachHeads");
            maxBeachheadsNode.InnerText = maxBeachHeads.ToString();
            nodeToReturn.AppendChild(specialActionsNode);
            nodeToReturn.AppendChild(maxSpecialActionsNode);
            nodeToReturn.AppendChild(beachheadsNode);
            nodeToReturn.AppendChild(maxBeachheadsNode);

            System.Xml.XmlNode blocksInPoolNode = xml.CreateElement("BlocksInPool");
            foreach(Block block in blocksInPool)
            {
                blocksInPoolNode.AppendChild(block.Serialise(xml));
            }
            nodeToReturn.AppendChild(blocksInPoolNode);

            System.Xml.XmlNode GSUInPoolNode = xml.CreateElement("GSUInPool");
            foreach (GroundSupportUnit GSU in GSUInPool)
            {
                GSUInPoolNode.AppendChild(GSU.Serialise(xml));
            }
            nodeToReturn.AppendChild(GSUInPoolNode);

            return nodeToReturn;
        }

        public static ForcePool Deserialise(System.Xml.XmlNode node)
        {
            ForcePool forcePoolToReturn = new ForcePool(MapInfo.CountryID.BalticStates);
            if(node.Name == "ForcePool")
            {
                forcePoolToReturn.country = (MapInfo.CountryID)Enum.Parse(typeof(MapInfo.CountryID), node.Attributes["Country"].Value);
                foreach(System.Xml.XmlNode forcePoolNode in node)
                {
                    switch(forcePoolNode.Name)
                    {
                        case "SpecialActions":
                            forcePoolToReturn.currentSpecialActions = Int32.Parse(forcePoolNode.InnerText);
                            break;
                        case "MaxSpecialActions":
                            forcePoolToReturn.maxSpecialActions = Int32.Parse(forcePoolNode.InnerText);
                            break;
                        case "BeachHeads":
                            forcePoolToReturn.currentBeachHeads = Int32.Parse(forcePoolNode.InnerText);
                            break;
                        case "MaxBeachHeads":
                            forcePoolToReturn.maxBeachHeads = Int32.Parse(forcePoolNode.InnerText);
                            break;
                        case "BlocksInPool":
                            foreach(System.Xml.XmlNode blockNode in forcePoolNode)
                            {
                                forcePoolToReturn.blocksInPool.Add(Block.Deserialise(blockNode));
                            }
                            break;
                        case "GSUInPool":
                            foreach (System.Xml.XmlNode GSUNode in forcePoolNode)
                            {
                                forcePoolToReturn.GSUInPool.Add(GroundSupportUnit.Deserialise(GSUNode));
                            }
                            break;
                    }
                }
            }
            return forcePoolToReturn;
        }

        public bool Equals(ForcePool forcePoolToCompare)
        {
            if(this.country != forcePoolToCompare.country)
                return false;
            if(this.currentSpecialActions != forcePoolToCompare.currentSpecialActions)
                return false;
            if(this.maxSpecialActions != forcePoolToCompare.maxSpecialActions)
                return false;
            if(this.currentBeachHeads != forcePoolToCompare.currentBeachHeads)
                return false;
            if(this.maxBeachHeads != forcePoolToCompare.maxBeachHeads)
                return false;
            if(this.blocksInPool.Count != forcePoolToCompare.blocksInPool.Count)
                return false;
            List<Block> listOfBlocksToCompare = new List<Block>(forcePoolToCompare.blocksInPool);
            foreach(Block block in this.blocksInPool)
            {
                bool found = false;
                foreach (Block blockToLookFor in listOfBlocksToCompare)
                {
                    if(block.Equals(blockToLookFor))
                    {
                        found = true;
                        listOfBlocksToCompare.Remove(blockToLookFor);
                        break;
                    }
                }
                if(!found)
                    return false;
            }

            if (this.GSUInPool.Count != forcePoolToCompare.GSUInPool.Count)
                return false;
            List<GroundSupportUnit> listOfGSUToCompare = new List<GroundSupportUnit>(forcePoolToCompare.GSUInPool);
            foreach (GroundSupportUnit GSU in this.GSUInPool)
            {
                bool found = false;
                foreach (GroundSupportUnit GSUToLookFor in listOfGSUToCompare)
                {
                    if (GSU.Equals(GSUToLookFor))
                    {
                        found = true;
                        listOfGSUToCompare.Remove(GSUToLookFor);
                        break;
                    }
                }
                if (!found)
                    return false;
            }

            return true;
        }
    }
}
